﻿using MongoDB.Driver;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.Entities;
using Sustainalytics.MongoDB.Extensions;
using Sustainalytics.Utils;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Web.Http;
using WebApi.OutputCache.V2;
using Sustainalytics.Auth.Claims;
using System.Linq;
using Newtonsoft.Json;
using Sustainalytics.Replication.Publisher;
using System.Web.Http.Cors;

namespace Sustainalytics.MostActiveReports.Service.Controllers
{
    [EnableCors(origins: "*", headers: "*", methods: "*")]
    [RoutePrefix("api/v1/MostActiveReport")]
    public class MostActiveReportController : ApiController
    {
        private readonly ConnectionStrings _connectionString = null;
        private readonly IMongoCollection<MostActiveReport> _mostActiveReportCollection = null;
        private readonly IMongoCollection<CorporateData> _corporateDataCollection = null;
        private readonly ServiceBusPublisher _serviceBusPublisher = null;

        public MostActiveReportController(
            ConnectionStrings connectionString,
            ServiceBusPublisher serviceBusPublisher,
            IMongoCollection<MostActiveReport> mostActiveReportCollection,
            IMongoCollection<CorporateData> corporateDataCollection)
        {
            _connectionString = connectionString;
            _mostActiveReportCollection = mostActiveReportCollection;
            _corporateDataCollection = corporateDataCollection;
            _serviceBusPublisher = serviceBusPublisher;
        }

        [Route("")]
        public HttpResponseMessage Get([FromUri]ListOptions listOptions)
        {
            listOptions = listOptions ?? ListOptions.Default;

            var result = new List<MostActiveReportDto>();

            var mostActiveReports = _mostActiveReportCollection
                .Find(x => x.LastUpdated >= DateTime.Now.AddDays(-7) && x.LastUpdated <= DateTime.Now)
                .SortByDescending(x => x.NumberOfDownloads)
                .ThenBy(mar => mar.CompanyName)
                .Skip(listOptions.Skip)
                .Limit(listOptions.Take)
                .ToListAsync()
                .Result;

            if (!mostActiveReports.Any())
                return Request.CreateResponse(HttpStatusCode.OK, result);

            var claims = ClaimsPrincipal.Current.Claims;

            var accountUniverses = claims.GetUniverseIds().Distinct().ToList();

            var companyIds = mostActiveReports.Select(x => x.Id);

            var corporateDataDictionary = _corporateDataCollection
                    .Find(x => companyIds.Contains(x.Id))
                    .Project<CorporateData>(Builders<CorporateData>.Projection
                        .Include(t => t.Id)
                        .Include(t => t.CompanyName)
                        .Include(t => t.CompanyNameUrlFriendly)
                        .Include(t => t.MainTicker)
                        .Include(t => t.MainExchange)
                        .Include(t => t.UniverseIds))
                    .ToList()
                    .ToDictionary(x => x.Id, x => x);

            foreach (var mar in mostActiveReports)
            {
                if (!corporateDataDictionary.TryGetValue(mar.Id, out CorporateData corporateData))
                    continue;    

                result.Add(new MostActiveReportDto()
                {
                    Id = mar.Id,
                    CompanyName = corporateData.CompanyName,
                    CompanyNameUrlFriendly = corporateData.CompanyNameUrlFriendly,
                    Exchange = corporateData.MainExchange,
                    Ticker = corporateData.MainTicker,
                    InUniverse = accountUniverses.Intersect(corporateData.UniverseIds).Any()
                });
            }

            return Request.CreateResponse(HttpStatusCode.OK, result);
        }

        [Route("{companyId}")]
        public HttpResponseMessage Post(Guid companyId)
        {
            try
            {
                var corporateData = _corporateDataCollection
                    .Find(x => companyId == x.Id)
                    .Project<CorporateData>(Builders<CorporateData>.Projection
                        .Include(t => t.Id)
                        .Include(t => t.CompanyName)
                        .Include(t => t.CompanyNameUrlFriendly)
                        .Include(t => t.MainTicker)
                        .Include(t => t.MainExchange)
                        .Include(t => t.UniverseIds))
                    .FirstOrDefault();

                if (corporateData == null)
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "The requested company was not found!");

                var mostActiveReport = _mostActiveReportCollection
                    .Find(x => x.Id == companyId && x.ReportType == ReportType.ComprehensiveReport)
                    .SortByDescending(x=> x.NumberOfDownloads)
                    .FirstOrDefault();

                if (mostActiveReport == null)
                {
                    mostActiveReport = new MostActiveReport
                    {
                        Id = corporateData.Id,
                        NumberOfDownloads = 1,
                        ReportType = ReportType.ComprehensiveReport,
                        LastUpdated = DateTime.Now,
                        CompanyName = corporateData.CompanyName,
                        CompanyNameUrlFriendly = corporateData.CompanyNameUrlFriendly,
                        UniverseIds = corporateData.UniverseIds,
                        MainExchange = corporateData.MainExchange,
                        MainTicker = corporateData.MainTicker
                    };
                }
                else
                {
                    mostActiveReport.NumberOfDownloads++;
                    mostActiveReport.LastUpdated = DateTime.UtcNow;
                    mostActiveReport.CompanyName = corporateData.CompanyName;
                    mostActiveReport.CompanyNameUrlFriendly = corporateData.CompanyNameUrlFriendly;
                    mostActiveReport.UniverseIds = corporateData.UniverseIds;
                    mostActiveReport.MainExchange = corporateData.MainExchange;
                    mostActiveReport.MainTicker = corporateData.MainTicker;
                }

                _mostActiveReportCollection.FindOneAndReplace(Builders<MostActiveReport>.Filter.Eq(x => x.Id, companyId),
                    mostActiveReport,
                    new FindOneAndReplaceOptions<MostActiveReport>
                    {
                        IsUpsert = true
                    });

                //Serialize report and send it trough Service Bus
                _serviceBusPublisher.SendMessage(
                    JsonConvert.SerializeObject(mostActiveReport),
                    ReplicationUtils.EntityType.MostActiveReport,
                    ReplicationUtils.Operation.RecordReportActivity);

                return Request.CreateResponse(HttpStatusCode.OK);
            }
            finally
            {
                var cache = Configuration.CacheOutputConfiguration().GetCacheOutputProvider(Request);
                cache.RemoveStartsWith(Configuration.CacheOutputConfiguration().MakeBaseCachekey("MostActiveReport", "Get"));
            }
        }
    }
}
